
package com.plian.system.aspect;

import cn.hutool.core.date.DateUtil;
import com.plian.Tools.*;
import com.plian.Tools.pagedata.UserData;
import com.plian.system.annotation.LogOperation;
import com.plian.system.entity.sys.Loginfo;
import com.plian.system.enumeratea.LogStatusEnum;
import com.plian.system.mapper.sys.LoginfoMapper;
import lombok.AllArgsConstructor;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.exception.ExceptionUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.http.HttpHeaders;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;

import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;

/**
 * 操作日志，切面处理类
 *

 */
@Aspect
@Component
@AllArgsConstructor
public class LogOperationAspect {
    private final LoginfoMapper loginfoMapper;

    @Pointcut("@annotation(com.plian.system.annotation.LogOperation)")
    public void logPointCut() {

    }

    @Around("logPointCut()")
    public Object around(ProceedingJoinPoint point) throws Throwable {
        long beginTime = System.currentTimeMillis();
        RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
        try {
            // 将注解value存入请求属性
            MethodSignature signature = (MethodSignature) point.getSignature();
            Method method = point.getTarget().getClass().getDeclaredMethod(signature.getName(), signature.getParameterTypes());
            LogOperation annotation = method.getAnnotation(LogOperation.class);
            if (requestAttributes != null) {
                requestAttributes.setAttribute("LOG_OPERATION_VALUE", annotation.value(), RequestAttributes.SCOPE_REQUEST);
            }

            //执行方法
            Object result = point.proceed();

            //执行时长(毫秒)
            long time = System.currentTimeMillis() - beginTime;
            //保存日志
            saveLog(point, time, LogStatusEnum.SUCCESS.value(),null);

            return result;
        } catch (Exception e) {
            // 设置标记，避免全局处理器重复记录
            if (requestAttributes != null) {
                requestAttributes.setAttribute("LOG_RECORDED", true, RequestAttributes.SCOPE_REQUEST);
            }
            //执行时长(毫秒)
            long time = System.currentTimeMillis() - beginTime;
            //保存日志
            saveLog(point, time, LogStatusEnum.FAIL.value(), ExceptionUtils.getStackTrace(e));

            throw e;
        }
    }

    @Async("ttlExecutor")
    protected void saveLog(ProceedingJoinPoint joinPoint, long time, Integer status, String errorInfo) throws Exception {
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        Method method = joinPoint.getTarget().getClass().getDeclaredMethod(signature.getName(), signature.getParameterTypes());
        LogOperation annotation = method.getAnnotation(LogOperation.class);

        Loginfo log = new Loginfo();

        if (annotation != null) {
            //注解上的描述
            log.setOperation(annotation.value());
        }

        //登录用户信息
        UserData user = TokenUtil.getUserData();
        if (user != null) {
            log.setUserId(user.getUserId());
            log.setUserName(user.getUserName());
        }

        log.setStatus(status);
        log.setRequestTime(DateUtil.date());
        log.setRequestDuration(time);
        //如果有异常，记录异常
        if(status == LogStatusEnum.FAIL.value()){
            log.setLogType(3);
            if(StringUtils.isNotBlank(errorInfo)) log.setErrorInfo(errorInfo);
        }else {
            log.setLogType(2);
        }

        //请求相关信息
        HttpServletRequest request = HttpContextUtils.getHttpServletRequest();
        log.setCallingInterface(request.getRequestURI());
        log.setRequestWay(request.getMethod());
        log.setIp(IpUtils.getIpAddr(request));
        log.setUserAgent(request.getHeader(HttpHeaders.USER_AGENT));

        //请求参数
        Object[] args = joinPoint.getArgs();
        try {
            String params = JsonUtils.toJsonString(args[0]);
            log.setRequestParams(params);
        } catch (Exception e) {

        }
        log.setId(UuidUtil.get32UUID());
        //保存到DB
        loginfoMapper.save(log);
    }
}